﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Xml.Serialization;
using ProgramMain.Database;
using ProgramMain.Database.SimpleOpticNetDBTableAdapters;
using ProgramMain.Layers;
using System.Threading.Tasks;

namespace ProgramMain.NetVis
{
    public class CrossBoxVis : EquipmentSerializer
    {
        [XmlIgnore]
        public Graphics GraphicsLayer;

       [XmlIgnore]
        public VisLayer Vis;

        private bool _visible = true;
        [XmlIgnore]
        public virtual bool Visible
        {
            get { return _visible; }
            set
            {
                _visible = value;
                body.Visible = value;
                FibresOne.ForEach(f => f.Visible = value);
            }
        }

        protected int GetFibreHeight()
        {
           return (int)(FibreRange.BaseHeight ); 
        }

        public virtual void ShiftFibre(Point bodyVirtualPoint)
        {
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < FibresOne.Count; i++)
            {
                FibreRange item = FibresOne[i];
                item.Enter = this.Enter;
                tasks.Add(Task.Factory.StartNew(delegate { item.CalcCoordinate(bodyVirtualPoint); }));
                // item.CalcCoordinate(bodyVirtualPoint);
            }
            Task.WaitAll(tasks.ToArray());
        }

        public void ShiftVirtualPoint (Size shiftVirtualPoint)
        {
            VirtualPoint += shiftVirtualPoint;
            if(body != null)
            {
                body.VirtualPoint = CalcBodyPoint();
                ShiftFibre(body.VirtualPoint);
            }
        }

        [XmlIgnore]
        public Point Location
        {
            get { return Vis.GetLocation(VirtualPoint); }
        }

        [XmlIgnore]
        public Size OutSite { get; private set; }

        [XmlIgnore]
        public SimpleOpticNetDB.EquipmentRow Row { get; private set; }

        [XmlIgnore]
        protected BodyRange body;

       [XmlIgnore]
        public List<FibreRange> FibresOne = new List<FibreRange>();

        private SimpleOpticNetDB.FibreDataTable _fibres;

        [XmlIgnore]
        public SimpleOpticNetDB.FibreDataTable Fibres
        { get { return _fibres; } }

        [XmlIgnore]
        public virtual Brush ColorRange { get { return Brushes.White; } }

        [XmlIgnore]
        public virtual int width { get { return 1; } }

        [XmlIgnore]
        public virtual bool FillRange { get { return false; } }

        [XmlIgnore]
        public string Caption { get; set; }

        [XmlIgnore]
        public string Hint { get; set; }

        public void SetRow(SimpleOpticNetDB.EquipmentRow row)
        {
            Row = row;
            if (Row != null)
            {
                ID = Row.ID;
                Caption = row.IsCaptionNull() ? "" : row.Caption;
            }
        }

        protected BodyType GetBodyType()
        {
            Type t = this.GetType();
            switch (t.Name)
            {
                case "CrossBoxVis" :
                    return BodyType.Cross;
                case   "CableBoxVis":
                    return BodyType.CableBox;
                case "CableViz":
                    return BodyType.Cable;
            }
            return BodyType.Cable;
        }

        protected virtual void CreateBody()
        {
            body = new BodyRange(Vis)
                       {
                           VirtualPoint = CalcBodyPoint(),
                           FibreCount = Fibres.Count,
                           Caption = this.Caption,
                           CurveElementID = this.ID,
                           ColorRange = this.ColorRange,
                           width = this.width,
                           FillRange = this.FillRange,
                           Hint = this.Hint
            };
            body.bodyType = GetBodyType();
            body.Equip = this;
        }
        
        public void CreateEquipment(int vertexID)
        {
            try
            {
                FibreTableAdapter fibreTableAdapter = new FibreTableAdapter();
                fibreTableAdapter.ClearBeforeFill = true;
                fibreTableAdapter.SelectCommandTimeout = Properties.Settings.Default.LongQueryTimeout;
                _fibres = fibreTableAdapter.GetData(ID, null, null, false, vertexID);
            }
            catch (Exception)
            {

            }

            CreateBody();
            CalcVirtualPoint();

        }

        protected virtual void DrawBody(Graphics graphics)
        {
           this.body.Draw(graphics);
        }

        public virtual void CreateFibre(int vertexID)
        {
            CreateEquipment(vertexID);
            int i = 0;
            foreach (SimpleOpticNetDB.FibreRow item in Fibres.Cast<SimpleOpticNetDB.FibreRow>())
            {
                FibreRange fibreRange = new FibreRange(Vis);
                fibreRange.Number = i;
                fibreRange.CurveElementID = ID;
                fibreRange.CurveElementKindID = this.CurveElementKindID;
                fibreRange.Enter = this.Enter;
                fibreRange.Row = item;
                fibreRange.CalcCoordinate(body.VirtualPoint);
                FibresOne.Add(fibreRange);
                i++;
            }
        }

        protected virtual void DrawFibre(Graphics graphics)
        {
            FibresOne.ForEach(item => item.Draw(graphics));
        }

        public virtual Size CalcSize()
        {
            return new Size(body.VirtualSize().Width + 10, body.LocationSize.Height + GetFibreHeight() + 10);
        }

        public virtual Point CalcBodyPoint()
        {
            Point res = Point.Empty;
            if (Enter == 1)
                res = VirtualPoint + new Size(1, 3);
            if (Enter == 2)
                res = VirtualPoint + new Size(1, FibreRange.BaseHeight);
            return res;
        }

        public virtual void CalcVirtualPoint()
        {
            if (body == null) return;
            EquipmentSerializer e = Vis.GetMapProperty(ID);
            if (e != null && e.VirtualPoint != Point.Empty)
            {
                VirtualPoint = e.VirtualPoint;
                Enter = e.Enter;
            }
            else
            {

                Size size = CalcSize();
                int q = 0;
                Math.DivRem(IndexMap, 4, out q);
                CrossBoxVis r = Vis.FindLocation(IndexMap, CurveElementKindID);
                switch (q)
                {
                    case 0:
                        VirtualPoint =
                            new Point((-1)*(size.Width + body.shift + (r != null ? Math.Abs(r.VirtualPoint.X) : 0)),
                                      (-1)*(size.Height + body.shift));
                        Enter = 2;
                        break;
                    case 1:
                        VirtualPoint =
                            new Point(body.shift + (r != null ? Math.Abs(r.VirtualPoint.X) + r.CalcSize().Width : 0),
                                      body.shift);
                        Enter = 1;
                        break;
                    case 2:
                        VirtualPoint =
                            new Point(body.shift + (r != null ? Math.Abs(r.VirtualPoint.X) + r.CalcSize().Width : 0),
                                      (-1)*(size.Height + body.shift));
                        Enter = 2;
                        break;
                    case 3:
                        VirtualPoint =
                            new Point((-1)*(size.Width + body.shift + (r != null ? Math.Abs(r.VirtualPoint.X) : 0)),
                                      body.shift);
                        Enter = 1;
                        break;
                }
            }
            if(ID == 15) {}
            body.VirtualPoint = CalcBodyPoint();
        }

        public void Draw(Graphics graphics)
        {
            if (graphics != null)
            {
                DrawFibre(graphics);
                DrawBody(graphics);

                OutSite = CalcSize();
            }
        }

    }
}